﻿#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/fcntl.h>
#include <asm/gpio.h>
#include<linux/uaccess.h>

struct gpio_desc{
	int gpio;
    char *name;
} ;

static struct gpio_desc gpios[2] = {
    {131, "led0", }, /*GPIO5_IO3*/
    //{132,"led1", },
};

/* 主设备号  */
static int major = 0;
static struct class *led_class;
int count = sizeof(gpios)/sizeof(gpios[0]);//led count


/* 实现对应的open/read/write等函数，填入file_operations结构体 */
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	int ret;
    char drv_buf[2];

    if (size != 2)
		return -EINVAL;

    ret = copy_from_user(drv_buf, buf, 1);//get led number from app
    
	
    if (drv_buf[0] >= count)
		return -EINVAL;
    
	/* get value*/
	drv_buf[1] = gpio_get_value(gpios[(int)drv_buf[0]].gpio);

	ret = copy_to_user(buf, drv_buf, 2);
	
	return 2;

}

static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
	int ret;
    char drv_buf[2];

    if (size != 2)
		return -EINVAL;

	ret = copy_from_user(drv_buf, buf, size); //get led number and on_off state from app
    //ret = copy_from_user(drv_buf, buf, 2);

    if (drv_buf[0] >= count)
		return -EINVAL;

    /* set value */
	gpio_set_value(gpios[(int)drv_buf[0]].gpio, drv_buf[1]);

	return 2;
}

/* 定义自己的file_operations结构体 */
static struct file_operations led_drv_fops = {
	.owner	 = THIS_MODULE,
	.read    = led_drv_read,
	.write   = led_drv_write,
};


/* 在入口函数 */
static int __init led_drv_init(void)
{
    int err = 0;
    int i;

    for(i = 0; i < count; i++)
	{
		/* get gpio*/
		err = gpio_request(gpios[i].gpio, gpios[i].name);
		if (err < 0) {
			printk("can not request gpio %s %d\n", gpios[i].name, gpios[i].gpio);
			return -ENODEV;
		}
		/* set direction */
		gpio_direction_output(gpios[i].gpio, 1);

	}
	
	/* 注册file_operations 	*/
	major = register_chrdev(0, "led_drv", &led_drv_fops); 

	led_class = class_create(THIS_MODULE, "led_drv_class");
	if (IS_ERR(led_class)) {
		unregister_chrdev(major, "led_drv");
		return PTR_ERR(led_class);
	}

	device_create(led_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
	
	return err;
}

/* 有入口函数就应该有出口函数：卸载驱动程序时，就会去调用这个出口函数 */
static void __exit led_drv_exit(void)
{
    int i;
    int count = sizeof(gpios)/sizeof(gpios[0]);

	device_destroy(led_class, MKDEV(major, 0));
	class_destroy(led_class);
	unregister_chrdev(major, "led_drv");
    for(i = 0; i < count; i++)
	{
		/* free GPIO*/
		gpio_free(gpios[i].gpio);
	}
}


/* 7. 其他完善：提供设备信息，自动创建设备节点                                     */

module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");


